#include <string.h>
#include <omnetpp.h>

using namespace omnetpp;

class sender:public cSimpleModule
{
private:
    int seq;
    cMessage *timeoutEvent;
    simtime_t timeout;
    cMessage *message;

    simtime_t txtime;
    simtime_t ack_time;
    simtime_t avg_time;

    cHistogram Avg_Time_Stats;
    cOutVector Avg_Time_Vector;

public:
    sender();
    virtual ~sender();

protected:
    virtual void initialize();
    virtual void handleMessage(cMessage *msg);
    virtual void sendCopyOf(cMessage *msg);
    virtual cMessage *generateNewMessage();
    virtual void finish();
};

Define_Module(sender);

sender::sender()
{
    timeoutEvent = NULL;
    message = NULL;
}

sender::~sender()
{
    cancelAndDelete(timeoutEvent);
    delete message;
}

cMessage *sender::generateNewMessage()
{
    txtime = simTime();
    char msgname[20];
    sprintf(msgname,"send-%d",++seq);
    cMessage *msg = new cMessage(msgname);
    return msg;
}

void sender::sendCopyOf(cMessage *msg)
{
    cMessage *copy = (cMessage *)msg->dup();
    send(copy,"out");
}

void sender::initialize()
{
    seq=0;
    timeout=1.0;
    timeoutEvent = new cMessage("timeoutEvent");

    txtime = 0;
    ack_time = 0;
    avg_time = 0;

    WATCH(txtime);
    WATCH(ack_time);

    Avg_Time_Stats.setName("avg_timeStats");
    Avg_Time_Vector.setName("avg_time");

    EV << "Sending initial message\n";

    message = generateNewMessage();

    sendCopyOf(message);

    scheduleAt(simTime()+timeout,timeoutEvent);
}

void sender::handleMessage(cMessage *msg)
{

    if(msg==timeoutEvent)
    {
        EV << "Timeout expired,re-sending message\n";
        sendCopyOf(message);
        scheduleAt(simTime()+timeout,timeoutEvent);
    }
    else
    {
        ack_time = simTime();
        avg_time = ack_time-txtime;
        Avg_Time_Vector.record(avg_time);
        Avg_Time_Stats.collect(avg_time);

        EV << "Received:" << msg->getName() << "\n";
        delete msg;

        EV << "Timer cancelled.\n";

        cancelEvent(timeoutEvent);
        delete message;

        message = generateNewMessage();
        sendCopyOf(message);

        scheduleAt(simTime()+timeout,timeoutEvent);
    }
}

void sender::finish()
{
    EV << "avg , mean:" << Avg_Time_Stats.getMean() << endl;
    EV << "avg , min:" << Avg_Time_Stats.getMin() << endl;
    EV << "avg , max:" << Avg_Time_Stats.getMax() << endl;
    EV << "avg , stddev:" << Avg_Time_Stats.getStddev() << endl;

    recordScalar("#tx time",txtime);
    recordScalar("#ack time",ack_time);

    Avg_Time_Stats.recordAs("avg time");
}


